package com.blogs.security;

import com.blogs.security.filter.AdminAuthenticationProcessingFilter;
import com.blogs.security.service.impl.CustomUserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * Description 权限控制
 *
 * @author hubiao
 * @since 2020-09-27 15:00
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private CustomUserDetailsServiceImpl customUserDetailsService;

    @Resource
    private AdminAuthenticationProcessingFilter adminAuthenticationProcessingFilter;

    @Resource
    private DataSource dataSource;

    /**
     * 认证用户的来源【内存/数据库】
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    }

    /**
     * 配置拦截规则
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //释放资源 指定拦截规则 指定自定义认证页面
        http.authorizeRequests()
                .antMatchers( "/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs",
                        "/home/**", "/admin/login", "/templates/blog/**", "/templates/error/**", "/templates/comm/**",
                        "/admin/css/**", "/admin/images/**", "/admin/editormd/**", "/admin/js/**", "/admin/plugins/**",
                        "/blog/**", "/error/**" )
                .permitAll()
                //  .antMatchers( "/**" ).hasAnyRole( "USER","ADMIN" ) 设置权限
                .anyRequest().authenticated()
                //and 表示新的配置开始
                .and()
                // 设置登陆页
                .formLogin().loginPage( "/admin/login" )
                .loginProcessingUrl( "/admin/login" )
                // 设置登陆成功页
                .defaultSuccessUrl( "/admin/index" )
                // 登录失败Url
                .failureUrl( "/admin/login/error" )
                .permitAll()
                .and()
                .logout()
                .invalidateHttpSession( true )
                .permitAll()
                // 然而第二天他又来了，却必须再次登录。于是就有了“记住我”这样的功能来方便用户使用
                // - cookie储存方式
                .and()
                .rememberMe()
                //设置操作表的Repository
                .tokenRepository( persistentTokenRepository() )
                //设置记住我的时间为7天
                .tokenValiditySeconds( 60 * 60 * 24 * 7 )
                //设置userDetailsService
                .userDetailsService( customUserDetailsService );
        //记住我结束

        // 自定义过滤器认证用户名密码
        http.addFilterAt( adminAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class );

        // 关闭CSRF跨域
        http.csrf().disable();
    }


    /**
     * 自动登录保存token
     *
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        //保存数据库表为persistent_logins
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource( dataSource );
        return tokenRepository;
    }

    /**
     * 区分用户不存在和密码错误
     *
     * @return
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setHideUserNotFoundExceptions( false );
        provider.setUserDetailsService( customUserDetailsService );
        provider.setPasswordEncoder( new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return s.equals( charSequence.toString() );
            }
        } );
        return provider;
    }

}
